
package com.jf.cloud.im.socket.app;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import com.jf.cloud.api.auth.bo.UserInfoInTokenBO;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.auth.feign.AccountFeignClient;
import com.jf.cloud.api.auth.feign.TokenFeignClient;
import com.jf.cloud.api.auth.vo.AuthAccountVO;
import com.jf.cloud.api.multishop.bo.EsShopDetailBO;
import com.jf.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.jf.cloud.api.multishop.feign.ShopUserFeignClient;
import com.jf.cloud.api.multishop.vo.ShopUserVO;
import com.jf.cloud.api.platform.feign.SysUserClient;
import com.jf.cloud.api.platform.vo.SysUserVO;
import com.jf.cloud.api.user.feign.UserFeignClient;
import com.jf.cloud.api.user.vo.UserApiVO;
import com.jf.cloud.common.cache.util.RedisUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.util.Json;
import com.jf.cloud.im.constants.Constant;
import com.jf.cloud.im.constants.MsgCode;
import com.jf.cloud.im.constants.SendType;
import com.jf.cloud.im.model.ImMsgBizUserHistory;
import com.jf.cloud.im.service.ImMsgBizSkillsService;
import com.jf.cloud.im.service.ImMsgBizUserHistoryService;
import com.jf.cloud.im.socket.multishop.ShopOnlineWebSocketServer;
import com.jf.cloud.im.socket.multishop.ShopWebSocketServer;
import com.jf.cloud.im.socket.platform.SysOnlineWebSocketServer;
import com.jf.cloud.im.socket.platform.SysWebSocketServer;
import com.jf.cloud.im.vo.ImMsgBizSkillsVO;
import com.jf.cloud.im.vo.MessageInfoVO;
import com.jf.cloud.im.vo.MsgItemVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 用户收到的消息
 * 10,"无法获取用户信息"
 * 11,"账户已在别处登录，请刷新"
 * 12,"对方不在线"
 * 13, "内容格式有误"
 *
 * @author zz
 */
@ServerEndpoint("/ua/im/websocket/{token}/{userId}")
@Component
public class UserWebSocketServer {
    private static final Logger log = LoggerFactory.getLogger(UserWebSocketServer.class);

    /**
     * UUID为key
     */
    public static final ConcurrentHashMap<String, Session> USER_MAP = new ConcurrentHashMap<>(256);

    private static TokenFeignClient tokenFeignClient;

    private static UserFeignClient userFeignClient;

    private static SysUserClient sysUserClient;

    private static ShopDetailFeignClient shopDetailFeignClient;

    private static AccountFeignClient accountFeignClient;

    private static ImMsgBizUserHistoryService imMsgBizUserHistoryService;

    private static ImMsgBizSkillsService imMsgBizSkillsService;

    private static ShopUserFeignClient shopUserFeignClient;

    public static void setApplicationContext(ApplicationContext applicationContext) {
        tokenFeignClient = applicationContext.getBean(TokenFeignClient.class);
        userFeignClient = applicationContext.getBean(UserFeignClient.class);
        sysUserClient = applicationContext.getBean(SysUserClient.class);
        shopDetailFeignClient = applicationContext.getBean(ShopDetailFeignClient.class);
        accountFeignClient = applicationContext.getBean(AccountFeignClient.class);
        imMsgBizUserHistoryService = applicationContext.getBean(ImMsgBizUserHistoryService.class);
        imMsgBizSkillsService = applicationContext.getBean(ImMsgBizSkillsService.class);
        shopUserFeignClient = applicationContext.getBean(ShopUserFeignClient.class);
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) throws IOException {
        token = Base64.decodeStr(token);
        ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = tokenFeignClient.checkToken(token);
        if (!userInfoInTokenVoServerResponseEntity.isSuccess()) {
            throw new LuckException(userInfoInTokenVoServerResponseEntity.getMsg());
        }
        UserInfoInTokenBO userInfoInToken = userInfoInTokenVoServerResponseEntity.getData();
        if (userInfoInToken == null) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CAN_NOT_FIND_USER_INFO, "无法获取用户信息")));
            }
            return;
        }

        // 如果原来就有token
        Session oldSession = USER_MAP.get(Constant.USER_PREFIX + userInfoInToken.getUserId());
        if (oldSession != null) {
            // 客户端收到301，关闭ws链接，弹出提示
            if (oldSession.isOpen()) {
                oldSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.LOGIN_IN_OTHER_PLACE, "账户已在别处登录，请刷新")));
                oldSession.close();
            }
        }

        USER_MAP.put(Constant.USER_PREFIX + userInfoInToken.getUserId(), session);
        RedisUtil.set(Constant.USER_PREFIX + userInfoInToken.getUserId(), "", 0);
        if (session.isOpen()) {
            session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success("ok")));
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("token") String token, @PathParam("userId") Long userId) {
        USER_MAP.remove(Constant.USER_PREFIX + userId);
        RedisUtil.del(Constant.USER_PREFIX + userId);
    }

    /**
     * 连接错误调用的方法
     */
    @OnError
    public void onError(Session session, @PathParam("token") String token, Throwable error, @PathParam("userId") Long userId) {
        USER_MAP.remove(Constant.USER_PREFIX + userId);
        RedisUtil.del(Constant.USER_PREFIX + userId);
    }

    /**
     * 收到客户端消息后调用的方法，该消息由用户发过来
     *
     * @param sourceMessage 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String sourceMessage, @PathParam("token") String token, Session session) throws IOException {
        token = Base64.decodeStr(token);
        ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = tokenFeignClient.checkToken(token);
        if (!userInfoInTokenVoServerResponseEntity.isSuccess()) {
            throw new LuckException(userInfoInTokenVoServerResponseEntity.getMsg());
        }
        UserInfoInTokenBO userInfoInToken = userInfoInTokenVoServerResponseEntity.getData();
        if (Objects.isNull(userInfoInToken)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CAN_NOT_FIND_USER_INFO, "无法获取用户信息")));
            }
            return;
        }

        if (StrUtil.isBlank(sourceMessage)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CONTENT_FORMAT_ERROR, "内容格式有误")));
            }
            return;
        }

        MessageInfoVO messageInfo = Json.parseObject(sourceMessage, MessageInfoVO.class);

        if (Objects.isNull(messageInfo)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CONTENT_FORMAT_ERROR, "内容格式有误")));
            }
            return;
        }

        // 保持心跳
        if (StrUtil.equals(messageInfo.getContent(), Constant.HEART_BEAT)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HEART_BEAT, "保持心跳")));
            }
            return;
        }

        Long bizId = messageInfo.getToId();
        Long userId = userInfoInToken.getUserId();
        ServerResponseEntity<UserApiVO> userApiResponse = userFeignClient.getInsiderUserData(userInfoInToken.getUserId());
        if (!userApiResponse.isSuccess()) {
            throw new LuckException(userApiResponse.getMsg());
        }
        UserApiVO user = userApiResponse.getData();

        // 判断用户是发送给商家客服还是平台客服
        switch (messageInfo.getSendType()) {
            case SendType.PLATFORM:
                sendToPlatform(bizId, session, messageInfo, userId, user);
                break;
            case SendType.SHOP:
                sendToShop(bizId, session, messageInfo, userId, user);
                break;
            default:
                break;
        }
    }

    public void sendToPlatform(Long bizId, Session session, MessageInfoVO messageInfo, Long userId, UserApiVO user) throws IOException {
        ServerResponseEntity<AuthAccountVO> authAccountResponse = accountFeignClient.getBySysTypeAndIsAdminAndTenantId(SysTypeEnum.PLATFORM.value(), 1, bizId);
        if (!authAccountResponse.isSuccess()) {
            throw new LuckException(authAccountResponse.getMsg());
        }
        if (Objects.isNull(authAccountResponse.getData())) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }
        AuthAccountVO authAccount = authAccountResponse.getData();
        ServerResponseEntity<SysUserVO> sysUserResponse = sysUserClient.getSysUserByUserId(authAccount.getUserId());
        if (!sysUserResponse.isSuccess()) {
            throw new LuckException(sysUserResponse.getMsg());
        }
        SysUserVO sysUser = sysUserResponse.getData();
        if (Objects.isNull(sysUser)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }
        // 获取消息历史
        if (Objects.nonNull(messageInfo.getHistory()) && Objects.equals(messageInfo.getHistory(), true)) {
            PageVO<MsgItemVO> msgItemPage = imMsgBizUserHistoryService.getUserPlatformHistory(sysUser, messageInfo, bizId, userId, user);
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HISTORY, msgItemPage)));
            }
            return;
        }
        // 标记消息已读
        if (Objects.nonNull(messageInfo.getRead()) && Objects.equals(messageInfo.getRead(), true)) {
            markIsRead(bizId, session, messageInfo, userId);
            return;
        }
        if (Objects.nonNull(messageInfo.getOnlineOrOffline()) && Objects.equals(messageInfo.getOnlineOrOffline(), true)) {
            sendOnlineMsg(bizId, session);
        }
        // 发送消息
        if (Objects.nonNull(messageInfo.getContent()) && !messageInfo.getContent().isEmpty()) {
            // 查出负责该客户的客服
            if (Objects.nonNull(RedisUtil.get(Constant.IN_CHARGE_SYS + userId))) {
                String tempSysUserId = RedisUtil.get(Constant.IN_CHARGE_SYS + userId);
                if (Objects.nonNull(tempSysUserId)) {
                    Long sysUserId = Long.valueOf(tempSysUserId.substring(4));
                    Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + sysUserId);
                    if (Objects.nonNull(sysSession)) {
                        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserPlatformHistory(messageInfo, bizId, userId, sysUserId);
                        sendMsgToSysUser(bizId, messageInfo, user, sysUser, sysUserId, sysSession, imMsgBizUserHistory);
                        List<Session> listSysUser2 = getSessionList(Constant.ONLINE_SYS_PREFIX + sysUserId + Constant.UNDERLINE + "*", Constant.ONLINE_SYS_PREFIX + sysUserId + Constant.UNDERLINE, SysOnlineWebSocketServer.SYS_ONLINE_MAP);
                        //sendNewMsg(listSysUser2, bizId, Constant.UNREAD_SYS_PREFIX);
                        return;
                    }
                    RedisUtil.del(Constant.IN_CHARGE_SYS + userId);
                }
            }
            // 如果没有跟进的客服或者跟进的客服不在线
            List<String> listSysUser = getListEmployee(Constant.SYS_PREFIX + "*", Constant.SYS_PREFIX);
            if (!listSysUser.isEmpty()) {
                Long sysUserId = getNewOnlineSysUser(bizId, messageInfo, userId, user, sysUser, listSysUser);
                List<Session> listSysUser2 = getSessionList(Constant.ONLINE_SYS_PREFIX + sysUserId + Constant.UNDERLINE + "*", Constant.ONLINE_SYS_PREFIX + sysUserId + Constant.UNDERLINE, SysOnlineWebSocketServer.SYS_ONLINE_MAP);
                //sendNewMsg(listSysUser2, sysUserId, Constant.UNREAD_SYS_PREFIX);
            } else {
                ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserPlatformHistory(messageInfo, bizId, userId, authAccount.getUserId());
                List<Session> listSysUser2 = getSessionList(Constant.ONLINE_SYS_PREFIX + "*", Constant.ONLINE_SYS_PREFIX, SysOnlineWebSocketServer.SYS_ONLINE_MAP);
                sendNewMsg(listSysUser2, imMsgBizUserHistory.getEmployeeId(), Constant.UNREAD_SYS_PREFIX);
            }
        }
        messagePlatform(bizId, messageInfo, user, (long) com.jf.cloud.common.constant.Constant.SUPER_ADMIN_ID, null);
    }

    private void sendMsgToSysUser(Long bizId, MessageInfoVO messageInfo, UserApiVO user, SysUserVO sysUser, Long sysUserId, Session sysSession, ImMsgBizUserHistory imMsgBizUserHistory) throws IOException {
        // 发送消息给平台
        imMsgBizUserHistory.setNickName(sysUser.getNickName());
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
        if (sysSession.isOpen()) {
            sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            messagePlatform(bizId, messageInfo, user, sysUserId, sysSession);
        }
    }

    private static Long getNewOnlineSysUser(Long bizId, MessageInfoVO messageInfo, Long userId, UserApiVO user, SysUserVO sysUser, List<String> listSysUser) throws IOException {
        // 随机选一个在线客服
        int index = (int) (Math.random() * listSysUser.size());
        long tempLength = (Constant.SYS_PREFIX).length();
        Long sysUserId = Long.valueOf(listSysUser.get(index).substring((int) tempLength));
        Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + sysUserId);
        RedisUtil.set(Constant.IN_CHARGE_SYS + userId, "test" + sysUserId, 0);
        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserPlatformHistory(messageInfo, bizId, userId, sysUserId);
        // 发送消息给平台
        imMsgBizUserHistory.setNickName(sysUser.getNickName());
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
        if (Objects.nonNull(sysSession)) {
            if (sysSession.isOpen()) {
                sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            }
        }
        return sysUserId;
    }

    private static void sendOnlineMsg(Long bizId, Session session) throws IOException {
        Set<String> set = RedisUtil.keys(Constant.ONLINE_SYS_PREFIX + "*");
        MsgItemVO msgItem = new MsgItemVO();
        msgItem.setOnlineOrOffline(!set.isEmpty());
        msgItem.setChatType(SendType.PLATFORM);
        msgItem.setShopId(bizId);
        if (session.isOpen()) {
            session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.ONLINE_OR_OFFLINE, msgItem)));
        }
    }

    private static void markIsRead(Long bizId, Session session, MessageInfoVO messageInfo, Long userId) throws IOException {
        if (Objects.nonNull(messageInfo.getMsgIds()) && !messageInfo.getMsgIds().isEmpty()) {
            List<ImMsgBizUserHistory> imMsgBizUserHistories = imMsgBizUserHistoryService.markUserPlatformRead(messageInfo, bizId, userId);
            if (!imMsgBizUserHistories.isEmpty()) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success("ok")));
                }
                if (Objects.nonNull(messageInfo.getReadNoticePlatformUserId())) {
                    Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + messageInfo.getReadNoticePlatformUserId());
                    if (Objects.nonNull(sysSession)) {
                        if (sysSession.isOpen()) {
                            sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                        }
                    }
                } else {
                    String tempSysUserId = RedisUtil.get(Constant.IN_CHARGE_SYS + userId);
                    if (Objects.nonNull(tempSysUserId)) {
                        long sysUserId = Long.parseLong(tempSysUserId.substring(4));
                        Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + sysUserId);
                        if (Objects.nonNull(sysSession)) {
                            if (sysSession.isOpen()) {
                                sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                            }
                        }
                    }
                }
            }
        }
    }

    private static void sendNewMsg(List<Session> listSysUser2, Long employeeId, String key) throws IOException {
        if (!listSysUser2.isEmpty()) {
            // 有新消息提示为半个小时
            RedisUtil.set(key + employeeId + Constant.UNDERLINE, 1, 1800);
            MsgItemVO msgItem2 = new MsgItemVO();
            msgItem2.setNewMessage(true);
            for (Session sysSession2 : listSysUser2) {
                if (Objects.nonNull(sysSession2)) {
                    if (sysSession2.isOpen()) {
                        sysSession2.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem2)));
                        RedisUtil.del(key + employeeId + Constant.UNDERLINE);
                    }
                }
            }
        }
    }

    private static List<Session> getSessionList(String prefix, String onlinePrefix, ConcurrentHashMap<String, Session> sysOnlineMap) {
        Set<String> set2 = RedisUtil.keys(prefix);
        List<Session> listSysUser2 = new ArrayList<>(com.jf.cloud.common.constant.Constant.INITIAL_CAPACITY);
        for (String key : set2) {
            if (key.startsWith(onlinePrefix)) {
                listSysUser2.add(sysOnlineMap.get(key));
            }
        }
        return listSysUser2;
    }

    public void sendToShop(Long bizId, Session session, MessageInfoVO messageInfo, Long userId, UserApiVO user) throws IOException {
        ServerResponseEntity<AuthAccountVO> authAccountResponse = accountFeignClient.getBySysTypeAndIsAdminAndTenantId(SysTypeEnum.MULTISHOP.value(), 1, bizId);
        if (!authAccountResponse.isSuccess()) {
            throw new LuckException(authAccountResponse.getMsg());
        }
        AuthAccountVO authAccount = authAccountResponse.getData();

        if (Objects.isNull(authAccount)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }

        ServerResponseEntity<EsShopDetailBO> shopResponse = shopDetailFeignClient.getShopByShopId(bizId);
        if (!shopResponse.isSuccess()) {
            throw new LuckException(shopResponse.getMsg());
        }
        EsShopDetailBO shopDetail = shopResponse.getData();

        if (Objects.isNull(shopDetail)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }

        // 获取消息历史
        if (Objects.nonNull(messageInfo.getHistory()) && Objects.equals(messageInfo.getHistory(), true)) {
            PageVO<MsgItemVO> msgItemPage = imMsgBizUserHistoryService.getUserShopHistory(shopDetail, messageInfo, bizId, userId, user);
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HISTORY, msgItemPage)));
            }
            return;
        }

        // 标记消息已读
        if (Objects.nonNull(messageInfo.getRead()) && Objects.equals(messageInfo.getRead(), true)) {
            markShopMsgIsRead(bizId, session, messageInfo, userId);
            return;
        }

        if (Objects.nonNull(messageInfo.getOnlineOrOffline()) && Objects.equals(messageInfo.getOnlineOrOffline(), true)) {
            sendShopOnlineMsg(bizId, session);
        }

        // 发送消息
        if (Objects.nonNull(messageInfo.getContent()) && !messageInfo.getContent().isEmpty()) {
            // 查出负责该客户的客服
            if (Objects.nonNull(RedisUtil.get(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId))) {
                String tempEmployeeId = RedisUtil.get(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId);
                if (Objects.nonNull(tempEmployeeId)) {
                    Long employeeId = Long.valueOf(tempEmployeeId.substring(4));
                    Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId);
                    if (Objects.nonNull(shopSession)) {
                        getOnlineShopUser(bizId, messageInfo, userId, user, shopDetail, employeeId, shopSession);
                        List<Session> listEmployee2 = getSessionList(Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId + Constant.UNDERLINE + "*", Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId + Constant.UNDERLINE, ShopOnlineWebSocketServer.SHOP_ONLINE_EMPLOYEE_MAP);
                        //sendNewMsg(listEmployee2, employeeId, Constant.UNREAD_SHOP_PREFIX);
                        return;
                    }
                    RedisUtil.del(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId);
                }
            }
            // 如果没有跟进的客服或者跟进的客服不在线
            List<String> listEmployee = getListEmployee(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + "*", Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE);
            if (!listEmployee.isEmpty()) {
                Long employeeId = getNewOnlineShopUser(authAccount.getUserId(), bizId, messageInfo, userId, user, shopDetail, listEmployee);
                List<Session> listEmployee2 = getSessionList(Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId + Constant.UNDERLINE + "*", Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId + Constant.UNDERLINE, ShopOnlineWebSocketServer.SHOP_ONLINE_EMPLOYEE_MAP);
                //sendNewMsg(listEmployee2, employeeId, Constant.UNREAD_SHOP_PREFIX);
            } else {
                ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserShopHistory(messageInfo, bizId, userId, authAccount.getUserId());
                List<Session> listEmployee2 = getSessionList(Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + "*", Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE, ShopOnlineWebSocketServer.SHOP_ONLINE_EMPLOYEE_MAP);
                sendNewMsg(listEmployee2, imMsgBizUserHistory.getEmployeeId(), Constant.UNREAD_SHOP_PREFIX);
            }

        }
        Long shopUserId = shopUserFeignClient.getShopUserIdByShopId(bizId).getData();
        messageShop(bizId, messageInfo, user, shopUserId, null, shopDetail);
    }

    private static List<String> getListEmployee(String prefix, String shopPrefix) {
        Set<String> set = RedisUtil.keys(prefix);
        List<String> listEmployee = new ArrayList<>(com.jf.cloud.common.constant.Constant.INITIAL_CAPACITY);
        for (String key : set) {
            if (key.startsWith(shopPrefix)) {
                listEmployee.add(key);
            }
        }
        return listEmployee;
    }

    private void getOnlineShopUser(Long bizId, MessageInfoVO messageInfo, Long userId, UserApiVO user, EsShopDetailBO shopDetail, Long employeeId, Session shopSession) throws IOException {
        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserShopHistory(messageInfo, bizId, userId, employeeId);

        // 获取客服昵称
        ServerResponseEntity<ShopUserVO> shopUserResponse = shopDetailFeignClient.getShopUserByShopUserId(employeeId);
        if (!shopUserResponse.isSuccess() || Objects.isNull(shopUserResponse.getData())) {
            throw new LuckException(shopUserResponse.getMsg());
        }
        ShopUserVO shopUserVO = shopUserResponse.getData();
        imMsgBizUserHistory.setNickName(shopUserVO.getNickName());
        // 发送消息给客服
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserShopMsgItem(shopDetail, user, imMsgBizUserHistory);
        if (shopSession.isOpen()) {
            shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            messageShop(bizId, messageInfo, user, employeeId, shopSession, shopDetail);
        }
    }

    private static Long getNewOnlineShopUser(Long shopEmployeeId, Long bizId, MessageInfoVO messageInfo, Long userId, UserApiVO user, EsShopDetailBO shopDetail, List<String> listEmployee) throws IOException {
        // 随机选一个在线客服
        int index = (int) (Math.random() * listEmployee.size());
        long tempLength = (Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE).length();
        Long employeeId = Long.valueOf(listEmployee.get(index).substring((int) tempLength));
        Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId);
        RedisUtil.set(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId, "test" + employeeId, 0);
        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserShopHistory(messageInfo, bizId, userId, employeeId);

        // 获取客服昵称
        ServerResponseEntity<ShopUserVO> shopUserResponse = shopDetailFeignClient.getShopUserByShopUserId(shopEmployeeId);
        if (!shopUserResponse.isSuccess()) {
            throw new LuckException(shopUserResponse.getMsg());
        }
        ShopUserVO shopUserVO = shopUserResponse.getData();
        imMsgBizUserHistory.setNickName(shopUserVO.getNickName());

        // 发送消息给客服
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserShopMsgItem(shopDetail, user, imMsgBizUserHistory);
        if (Objects.nonNull(shopSession)) {
            if (shopSession.isOpen()) {
                shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            }
        }
        return employeeId;
    }

    private static void sendShopOnlineMsg(Long bizId, Session session) throws IOException {
        Set<String> set = RedisUtil.keys(Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + "*");
        MsgItemVO msgItem = new MsgItemVO();
        msgItem.setChatType(SendType.SHOP);
        msgItem.setShopId(bizId);
        msgItem.setOnlineOrOffline(!set.isEmpty());
        if (session.isOpen()) {
            session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.ONLINE_OR_OFFLINE, msgItem)));
        }
    }

    private static void markShopMsgIsRead(Long bizId, Session session, MessageInfoVO messageInfo, Long userId) throws IOException {
        if (Objects.nonNull(messageInfo.getMsgIds()) && !messageInfo.getMsgIds().isEmpty()) {
            List<ImMsgBizUserHistory> imMsgBizUserHistories = imMsgBizUserHistoryService.markUserShopRead(messageInfo, bizId, userId);
            if (!imMsgBizUserHistories.isEmpty()) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, "ok")));
                }
                if (Objects.nonNull(messageInfo.getReadNoticeEmployeeId())) {
                    Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + messageInfo.getReadNoticeEmployeeId());
                    if (Objects.nonNull(shopSession)) {
                        if (shopSession.isOpen()) {
                            shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                        }
                    }
                } else {
                    String tempEmployeeId = RedisUtil.get(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId);
                    if (Objects.nonNull(tempEmployeeId)) {
                        long employeeId = Long.parseLong(tempEmployeeId.substring(4));
                        Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId);
                        if (Objects.nonNull(shopSession)) {
                            if (shopSession.isOpen()) {
                                shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                            }
                        }
                    }
                }
            }
        }
    }

    private void messageShop(Long bizId, MessageInfoVO messageInfo, UserApiVO user, Long employeeId, Session shopSession, EsShopDetailBO shopDetail) throws IOException {
        String content = messageInfo.getContent();
        if (content != null && !content.contains(Constant.BRACE_LEFT) && !content.contains(Constant.BRACE_RIGHT) && !content.contains(Constant.IM)
                && !content.contains(".jpg") && !content.contains(".png") && !content.contains(".gif")
                && !"/".equals(content.substring(0, 1))) {
            List<ImMsgBizSkillsVO> imMsgBizSkills = imMsgBizSkillsService.getByShopId(bizId);
            if (Objects.nonNull(imMsgBizSkills) && imMsgBizSkills.size() != 0) {
                Map<String, String> collect = imMsgBizSkills.stream().collect(Collectors.toMap(ImMsgBizSkillsVO::getKeywords, ImMsgBizSkillsVO::getContent));
                for (Map.Entry<String, String> entry : collect.entrySet()) {
                    if (content.contains(entry.getKey())) {
                        MessageInfoVO msg = new MessageInfoVO();
                        msg.setMsgType(0);
                        msg.setToId(user.getUserId());
                        msg.setContent(entry.getValue());
                        UserInfoInTokenBO userInfoInToken = new UserInfoInTokenBO();
                        userInfoInToken.setTenantId(bizId);
                        userInfoInToken.setUserId(employeeId);
                        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveShopUserHistory(msg, userInfoInToken);
                        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserShopMsgItem(shopDetail, user, imMsgBizUserHistory);
                        // 在线的话发送消息，不在线的话留言
                        sendMsgUser(shopSession, msg, msgItem);
                    }
                }
            }
        }
    }

    private void messagePlatform(Long bizId, MessageInfoVO messageInfo, UserApiVO user, Long employeeId, Session sysSession) throws IOException {
        String content = messageInfo.getContent();
        if (content != null && !content.contains(Constant.BRACE_LEFT) && !content.contains(Constant.BRACE_RIGHT) && !content.contains(Constant.IM)
                && !content.contains(".jpg") && !content.contains(".png") && !content.contains(".gif")
                && !"/".equals(content.substring(0, 1))) {
            List<ImMsgBizSkillsVO> imMsgBizSkills = imMsgBizSkillsService.getByShopId(bizId);
            if (Objects.nonNull(imMsgBizSkills) && imMsgBizSkills.size() != 0) {
                Map<String, String> collect = imMsgBizSkills.stream().collect(Collectors.toMap(ImMsgBizSkillsVO::getKeywords, ImMsgBizSkillsVO::getContent));
                for (Map.Entry<String, String> entry : collect.entrySet()) {
                    if (content.contains(entry.getKey())) {
                        MessageInfoVO msg = new MessageInfoVO();
                        msg.setMsgType(0);
                        msg.setToId(user.getUserId());
                        msg.setContent(entry.getValue());
                        UserInfoInTokenBO userInfoInToken = new UserInfoInTokenBO();
                        userInfoInToken.setUserId(employeeId);
                        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.savePlatformUserHistory(msg, userInfoInToken);
                        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
                        sendMsgUser(sysSession, msg, msgItem);
                    }
                }
            }
        }
    }

    private static void sendMsgUser(Session sysSession, MessageInfoVO msg, MsgItemVO msgItem) throws IOException {
        Session userSession = USER_MAP.get(Constant.USER_PREFIX + msg.getToId());
        if (userSession.isOpen()) {
            userSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
        }
        if (sysSession != null) {
            sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
        }
    }


}
